/*
 *  Copyright (C) 2009 Antonio Mata Chamorro
 *  
 *  Este programa es software libre: usted puede redistribuirlo y/o modificarlo
 *  bajo los t�rminos de la Licencia P�blica General GNU publicada
 *  por la Fundaci�n para el Software Libre, ya sea la versi�n 3
 *  de la Licencia, o (a su elecci�n) cualquier versi�n posterior.
 *  
 *  Este programa se distribuye con la esperanza de que sea �til, pero 
 *  SIN GARANT�A ALGUNA; ni siquiera la garant�a impl�cita
 *  MERCANTIL o de APTITUD PARA UN PROP�SITO DETERMINADO. 
 *  Consulte los detalles de la Licencia P�blica General GNU para obtener 
 *  una informaci�n m�s detallada. 
 *  
 *  Deber�a haber recibido una copia de la Licencia P�blica General GNU
 *  junto a este programa. 
 *  En caso contrario, consulte <http://www.gnu.org/licenses/>.
 *   
 */
package org.javahispano.javacup.tacticas_aceptadas.amata.com.amata.javacup.tacticas;

import org.javahispano.javacup.modelo.Constantes;
import org.javahispano.javacup.modelo.Posicion;

/**
 * Esta clase calcula cual es el siguiente autopase que el jugador puede
 * realizar. Para esto se tiene en cuenta la cercania de jugadores contrarios a
 * este jugador y lo cerca que los jugadores contrarios se encontran de la
 * pelota despu�s del autopase.
 * <p/>
 * 
 * El proceso consiste en considerar 8 direcciones alrededor del jugador actual
 * que se corresponderian con norte, nortoeste, oeste y as�. Se determina la
 * distancia a la que se lanza el bal�n con el autopase seg�n el par�metro del
 * jugador AutoPassForce. Para cada direccion se calcula las posibilidades de
 * que un jugador contrario de llege a la pelota antes que nuestro jugador.
 * Finalmente si el jugador actual se encuentra demasiado cerca de un jugador
 * contrario el mejor autopase consigue un valor 0, es decir se desestimara el
 * autopase.
 * 
 * @see SoccerPlayer#getAutoPassForce()
 * @see SoccerMatchConfiguration#getAutoPassDegradationWeight()
 * @see SoccerMatchConfiguration#getOpponentMinDistance()
 * @see SoccerMatchConfiguration#getDefenderMinDistance()
 * 
 * @author Antonio Mata Chamorro
 * 
 * */
public class AutoPassSpotCalculator implements SpotCalculator {
	/**
	 * Si la fuerza de un jugador se fija a m�xima el bal�n recorre esta
	 * distancia. Fue calculada con el Asistente
	 * */
	private final static double FACTOR_DISTANCE_FORCE = 25f;

	private float autoPassDegradationWeight = 0.9f;
	private float opponentMinDistance = (float) Constantes.DISTANCIA_CONTROL_BALON * 2;
	private float defenderMinDistance = (float) Constantes.DISTANCIA_CONTROL_BALON * 6;

	private final static int NUM_DIRECTIONS = 8;
	private Posicion[] directions = new Posicion[NUM_DIRECTIONS];
	private float[] weight = new float[] { 0.9f, 0.8f, 0.5f, 0.2f, 0.1f, 0.2f,
			0.5f, 0.8f };
	private Posicion aux = new Posicion();

	public AutoPassSpotCalculator(SoccerMatchConfiguration configuration) {
		directions[0] = new Posicion(0, 1);
		directions[1] = new Posicion(1, 1);
		directions[2] = new Posicion(1, 0);
		directions[3] = new Posicion(1, -1);
		directions[4] = new Posicion(0, -1);
		directions[5] = new Posicion(-1, -1);
		directions[6] = new Posicion(-1, 0);
		directions[7] = new Posicion(-1, 1);

		this.autoPassDegradationWeight = configuration
				.getAutoPassDegradationWeight();
		this.opponentMinDistance = configuration.getOpponentMinDistance();
		this.defenderMinDistance = configuration.getDefenderMinDistance();

	}

	public void findSpots(SoccerPlayer player, SpotResults results) {
		double distance = player.getAutoPassForce() * FACTOR_DISTANCE_FORCE;

		// por defecto auto pase hacia adelante
		Spot spot = new Spot(new Posicion(player.getPosicion().getX()
				+ (directions[0].getX() * distance), player.getPosicion()
				.getY()
				+ (directions[0].getY() * distance)));
		spot.setValue(0);

		// calcular distancia de un jugador contrario al jugador actual
		double distanceToPlayer = Constantes.LARGO_CAMPO;
		for (SoccerPlayer p : player.getTeam().getOppositeTeam().getPlayers()) {
			distanceToPlayer = Math.min(distanceToPlayer, p.getPosicion()
					.distancia(player.getPosicion()));
		}
		// 0 si alg�n defensor estan entro de la distancia de control y 1 si
		// cualquier defensor estan por encima de defenderMinDistance
		float factor = distanceToPlayer < Constantes.DISTANCIA_CONTROL_BALON
				|| distanceToPlayer < defenderMinDistance ? 0 : 1;

		for (int i = 0; i < directions.length; i++) {
			aux = player.getPosicion().moverPosicion(
					directions[i].getX() * distance,
					directions[i].getY() * distance);

			// si el autopase hace salir la pelota del campo de juego lo
			// desestimamos
			if (Math.abs(aux.getX()) > Constantes.ANCHO_CAMPO_JUEGO / 2
					|| Math.abs(aux.getY()) > Constantes.LARGO_CAMPO_JUEGO / 2)
				continue;

			// encontrar la distancia m�nima a la que se encuentra un contrario
			// despu�s del autopase
			double minOpponentDistanceToBall = Constantes.LARGO_CAMPO;
			for (SoccerPlayer p : player.getTeam().getOppositeTeam()
					.getPlayers()) {
				minOpponentDistanceToBall = Math.min(minOpponentDistanceToBall,
						p.getPosicion().distancia(aux));
			}

			// si ningun contrario estara mas cerca de nosotros de la pelota y
			// mejoramos los resultamos el autopase es bueno
			if ((minOpponentDistanceToBall - distance > opponentMinDistance)
					&& spot.getValue() < weight[i]) {
				// si el jugador actual es actual es el portero no debe salir
				// del radio de su porter�a
				if (!(player.getDetalle().esPortero() && Constantes.centroArcoInf
						.distancia(aux) > Constantes.LARGO_AREA_GRANDE)) {
					spot.setPosicion(aux);
					spot.setValue(weight[i]);
				}
			}

		}
		spot.setValue(spot.getValue() * factor);

		spot.setValue(spot.getValue() * autoPassDegradationWeight);
		// solo devolvemos el punto de auto pase con mejor puntuaci�n. Si no
		// encontramos ninguno 0.
		results.addSpot(spot);
	}
}
